#include "ADUPipe.h"
#include "ADUFlow.h"
#include "ADUConstant.h"


PipeCircle* PipeCircle::createPipeCircle(const string& file) {
	PipeCircle* sprite = new PipeCircle();
	if(sprite && sprite->initWithFile(file)) {
		sprite->SetGamePaused(false);
		sprite->autorelease();
        return sprite;
    }
    CC_SAFE_DELETE(sprite);
    return nullptr;
}

void PipeCircle::enableTouch() {
	mTouchListener = EventListenerTouchOneByOne::create();
//	mTouchListener->setSwallowTouches(true);
	mTouchListener->onTouchBegan = CC_CALLBACK_2(PipeCircle::onTouchBegan, this);
	mTouchListener->onTouchMoved = CC_CALLBACK_2(PipeCircle::onTouchMoved, this);
	mTouchListener->onTouchEnded = CC_CALLBACK_2(PipeCircle::onTouchEnded, this);
	mTouchListener->onTouchCancelled = CC_CALLBACK_2(PipeCircle::onTouchCancelled, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(mTouchListener, this);

}

bool PipeCircle::onTouchBegan(Touch *touch, Event *event) {
	if (mGamePaused) return true;
	Rect boundingBox = this->getBoundingBox();
	Size circleSize = this->getContentSize();
	
	if(boundingBox.containsPoint(touch->getLocation())) {
		mCircleTouch = true;
		mPipeHeadTouch = false;
		// TUTORIAL ////////////////////////////////////////////////////////////////////
		if(UserDefault::getInstance()->getBoolForKey(TUTORIAL_KEY, false) == false) {
			if(Utils::tutorialStep == 0) {
				if(this->getChildByTag(TUTORIAL_TAG)) {
			        this->removeChildByTag(TUTORIAL_TAG);
		   		}
		   		if(this->getChildByTag(TUTORIAL_TEXT_TAG)) {
		   			this->removeChildByTag(TUTORIAL_TEXT_TAG);
		   		}
		   		Utils::tutorialStep++;
			}
   		}
   		// TUTORIAL ////////////////////////////////////////////////////////////////////

	} else if(mPipeHead && mPipeHead->getBoundingBox().containsPoint(touch->getLocation())) {
		mCircleTouch = false;
		mPipeHeadTouch = true;	
		// TUTORIAL ////////////////////////////////////////////////////////////////////
		if(UserDefault::getInstance()->getBoolForKey(TUTORIAL_KEY, false) == false) {
			if(Utils::tutorialStep == 1) {
				if(this->getChildByTag(TUTORIAL_TAG)) {
			        this->removeChildByTag(TUTORIAL_TAG);
		   		}
		   		if(this->getChildByTag(TUTORIAL_TEXT_TAG)) {
		   			this->removeChildByTag(TUTORIAL_TEXT_TAG);
		   		}
		   		Utils::tutorialStep++;
		   		UserDefault::getInstance()->setBoolForKey(TUTORIAL_KEY, true);
		   		UserDefault::getInstance()->flush();
			}
   		}
   		// TUTORIAL ////////////////////////////////////////////////////////////////////
	} else {
		mCircleTouch = false;
		mPipeHeadTouch = false;	
	}

	mHand = Sprite::create("images/hand.png");
    mHand->setTag(HAND_TAG);
    mHand->setPosition(event->getCurrentTarget()->convertToNodeSpace(touch->getLocation()));
    this->addChild(mHand);
	return true;
}

void PipeCircle::UpdateFlowPosition() {
    float a = mPipeHead->getRotation();
    a = a * PI / 180;
    
    auto x = mPipeHead->getPositionX() + mHeadLen * cos(a);
    auto y = mPipeHead->getPositionY() - mHeadLen * sin(a);
    Vec2 pos;
    pos.set(x, y);
    mFlow->updatePosition(pos);

}

void PipeCircle::onTouchMoved(Touch* touch, Event* event) {
	if (mGamePaused) return;
	Size circleSize = this->getContentSize();

    if(mHand) {
        mHand->setPosition(event->getCurrentTarget()->convertToNodeSpace(touch->getLocation()));
    } 
	if(mCircleTouch) {
		auto deltaX = touch->getDelta().x;
		auto deltaY = touch->getDelta().y;
        AdjustPipePostion(deltaX, deltaY);
		

	} else if(mPipeHeadTouch) {
		// Rotate pipe head
		auto diffPoint = mPipeHead->getPosition() - touch->getLocation();
		auto angleRadians = atan2f(diffPoint.y,diffPoint.x);

		mPipeHead->setAnchorPoint(Vec2(0,0.5));
		mPipeHead->setRotation(this->getRotation() - 180 - angleRadians * 180 / M_PI);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
		if(mFlow) {
			UpdateFlowPosition();
			mFlow->mEmitter->SetAngle(mPipeHead->getRotation());
		}
#endif
	}
}

void PipeCircle::AdjustPipePostion(float deltaX, float deltaY){
    auto visibleSize = Director::getInstance()->getVisibleSize();
    auto curX = this->getPositionX();
    auto curY = this->getPositionY();
    if((curY + deltaY) <= mWater->getHeight() + Utils::basinHeight || (curY + deltaY) >= visibleSize.height - 20.0f) return;
    this->setPosition(curX + deltaX, curY + deltaY);
    if(mPipeLine) {
        auto x = mPipeLine->getPositionX();
        auto y = mPipeLine->getPositionY();
        mPipeLine->setPosition(x + deltaX, y + deltaY);
    }
    
    if(mPipeHead) {
        auto x = mPipeHead->getPositionX();
        auto y = mPipeHead->getPositionY();
        mPipeHead->setPosition(x + deltaX, y + deltaY);
    }
    
    if (mFlow) {
        UpdateFlowPosition();
        
    }
}

void PipeCircle::SetFlow(Flow* flow) {
	mFlow = flow;
	if (mFlow) {
		UpdateFlowPosition();
		if(mFlow->mEmitter) {
            mFlow->mEmitter->SetAngle(mPipeHead->getRotation());
		}
		
	}
}

void PipeCircle::onTouchEnded(Touch* touch, Event* event) {
	if (mGamePaused) return;
	mCircleTouch = false;
	mPipeHeadTouch = false;	
	if(this->getChildByTag(HAND_TAG)) {
        this->removeChildByTag(HAND_TAG);
    }
    // TUTORIAL ////////////////////////////////////////////////////////////////////
	if(UserDefault::getInstance()->getBoolForKey(TUTORIAL_KEY, false) == false) {
		if(Utils::tutorialStep == 1) {
			Size circleSize = this->getContentSize();
			float circleW = circleSize.width;
			float circleH = circleSize.height;

			Size pipeHeadSize = mPipeHead->getContentSize();
			float pipeHeadW = pipeHeadSize.width;
			float pipeHeadH = pipeHeadSize.height;

			Sprite* arrowTut = Sprite::create(ARROW_TUT_IMG);
			arrowTut->setPosition(circleW + pipeHeadW, circleH/2);
			arrowTut->setTag(TUTORIAL_TAG);
			this->addChild(arrowTut, Z_PIPECIRCLE + 1);

			Text* tutText = Text::create("Rotate Pipe", FONT, FONT_SIZE * SCALE_FACTOR);
		    tutText->setPosition(Vec2(circleW + pipeHeadW, circleH/2 + arrowTut->getContentSize().height));
		    tutText->setColor(Color3B(255,222,2));
		    tutText->setTag(TUTORIAL_TEXT_TAG);
		    this->addChild(tutText, Z_PIPECIRCLE);
    	} 
	}
	// END TUTORIAL ////////////////////////////////////////////////////////////////////
}

void PipeCircle::onTouchCancelled(Touch* touch, Event* event) {
}

/////////////////// END PIPE_CIRCLE /////////////////////////////////////////////////////////


PipeHead* PipeHead::createPipeHead(const string& file) {
	PipeHead* sprite = new PipeHead();
	if(sprite && sprite->initWithFile(file)) {
		sprite->setAnchorPoint(Vec2(0,0.5));
		sprite->autorelease();
        return sprite;
    }
    CC_SAFE_DELETE(sprite);
    return nullptr;
}

void PipeHead::AddPhysic(){
    
    b2BodyDef bodyDef;
    
    this->setTag(TAG_PIPEHEAD);
    
    bodyDef.type = b2_kinematicBody;
    bodyDef.position.Set(this->getPositionX()/PTM_RATIO, this->getPositionY()/PTM_RATIO);
    bodyDef.userData = this;
    
    b2PolygonShape shape;
    float spriteWidth = this->getContentSize().width;
    float spriteHeight = this->getContentSize().height;
    shape.SetAsBox(0.5*spriteWidth/PTM_RATIO, 0.5*spriteHeight/PTM_RATIO);
    
	b2FixtureDef fixtureDef;
    fixtureDef.shape = &shape;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.0f;
    fixtureDef.restitution = 1.0f;
    
    mBody = (GameManager::getInstance()->mWorld)->CreateBody(&bodyDef);
    mBody->CreateFixture(&fixtureDef);
}


/////////////////// END PIPE_HEAD /////////////////////////////////////////////////////////

void Pipe::Update(float dt){
    mPipeCircle->AdjustPipePostion(0,(dt*GameManager::getInstance()->gameLevel)/2);
    mPipeCircle->UpdateFlowPosition();
}

void Pipe::createPipe(Node * _layer) {
	auto 	_visibleSize = Director::getInstance()->getVisibleSize();
    auto 	_origin = Director::getInstance()->getVisibleOrigin();
    auto 	_centerX = _origin.x + _visibleSize.width/2;
    auto 	_centerY = _origin.y + _visibleSize.height/2;

	mPipeLine = SpriteBatchNode::create(IMG_PIPE_LINE,NUM_PIPE_LINE);

	
	auto 	_winSize = Director::getInstance()->getWinSize();
	auto 	_widthScreen = _winSize.width;
	auto 	_heightScreen = _winSize.height;
	auto 	_pipeSize = mPipeLine->getContentSize();
	auto 	_pipeWidth = _pipeSize.width;
	auto 	_pipeHeight = _pipeSize.height;
	auto 	_anchorPoint = mPipeLine->getAnchorPoint();
	auto 	_pipeSegWidth = mPipeLine->getTexture()->getContentSize().width;
	mPipeLine->setPosition(Vec2(-(NUM_PIPE_LINE - 0.683) * _pipeSegWidth,0.79*_centerY));
	// Add PipeLine

	for(int i = 0; i < NUM_PIPE_LINE; i++) 	
	{		
		auto _pipeSegX = _pipeSegWidth/2 + i * _pipeSegWidth;
		auto _pipeSegY = _pipeHeight * _anchorPoint.y;
		if(i == NUM_PIPE_LINE - 1) {
			mLastSegPos.x = _pipeSegX;
			mLastSegPos.y = _pipeSegY;
		}
		mPipeSeg[i] = Sprite::createWithTexture(mPipeLine->getTexture());
		mPipeSeg[i]->setPosition(Vec2(_pipeSegX,_pipeSegY));
		mPipeLine->addChild(mPipeSeg[i]);
	}
	_layer->addChild(mPipeLine, Z_PIPE);

	

	// Add PipeCircle
	mPipeCircle = PipeCircle::createPipeCircle(IMG_PIPE_CIRCLE);
	float _circleWidth = mPipeCircle->getContentSize().width;
	float _circleHeight = mPipeCircle->getContentSize().height;
	mPipeCircle->setPosition(Vec2(mPipeLine->getPositionX() + mLastSegPos.x + _pipeSegWidth/2,mPipeLine->getPositionY()));
	_layer->addChild(mPipeCircle,Z_PIPECIRCLE);

	// TUTORIAL ////////////////////////////////////////////////////////////////////
	if(UserDefault::getInstance()->getBoolForKey(TUTORIAL_KEY, false) == false) {
		Sprite* handTut = Sprite::create("images/hand.png");
		handTut->setPosition(_circleWidth/2, _circleHeight/2);
		handTut->setTag(TUTORIAL_TAG);
		mPipeCircle->addChild(handTut, Z_PIPECIRCLE + 1);

		Text* tutText = Text::create("Move Pipe", FONT, FONT_SIZE * SCALE_FACTOR);
	    tutText->setPosition(Vec2(_circleWidth/2, _circleHeight + FONT_SIZE * SCALE_FACTOR));
	    tutText->setColor(Color3B(255,222,2));
	    tutText->setTag(TUTORIAL_TEXT_TAG);
	    mPipeCircle->addChild(tutText, Z_PIPECIRCLE);
	}
	// TUTORIAL ////////////////////////////////////////////////////////////////////
	
	// Add PipeHead
	mPipeHead = PipeHead::createPipeHead(IMG_PIPE_HEAD);
	mPipeHead->setPosition(mPipeCircle->getPositionX() + _circleWidth/8 ,mPipeLine->getPositionY());
    mPipeHead->setRotation(33);
    mPipeHead->AddPhysic();
	_layer->addChild(mPipeHead,Z_PIPE);

	mPipeCircle->setPipeHead(mPipeHead);
	mPipeCircle->setPipe(mPipeLine);
	mPipeCircle->enableTouch();

}

bool Pipe::isPipeTouched(Vec2 point){
	if (mPipeCircle->getBoundingBox().containsPoint(point)) return true;
	if (mPipeHead->getBoundingBox().containsPoint(point)) return true;
	return false;
}
void Pipe::follow(Node* follower, Node* target) {
    Size visibleSize = Director::getInstance()->getWinSize();	
	follower->runAction(Follow::create(target,Rect(0,0,visibleSize.width*NUM_BACKGROUND,visibleSize.height)));	
}

void Pipe::followDuck(Node* duck) {
	follow(mPipeLine, duck);
	follow(mPipeCircle, duck);
	follow(mPipeHead, duck);
}
